package com.xuzm.netty.test;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.Data;
import lombok.SneakyThrows;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;

public class NettyClient {
    public void start(Function<ChannelHandlerContext, String> msgFunction,D d) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 使用换行为分隔符
                            ch.pipeline().addLast(new LineBasedFrameDecoder(8192));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new StringEncoder());
                            // 添加自定义的ChannelHandler处理器
                            ch.pipeline().addLast(new ClientCustomChannelHandler(msgFunction));
                        }
                    });

            AtomicBoolean flag = new AtomicBoolean(false);
            CountDownLatch downLatch = new CountDownLatch(1);
            ChannelFuture channelFuture = bootstrap.connect("localhost", 8099)
                    .addListener(getChannelFutureListener(downLatch, flag)).sync();
//            ChannelFuture channelFuture = bootstrap.connect("39.100.129.15", 22122).sync();
            Channel channel = channelFuture.channel();
            downLatch.await();
            if(flag.get()) {
                d.setChannel(channel);
                d.getDownLatch().countDown();
            }
            channel.closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 连接的监听器
     */
    private ChannelFutureListener getChannelFutureListener(CountDownLatch downLatch, AtomicBoolean flag) {
        return future -> {
            if (future.isSuccess()) {
                flag.set(true);
                System.out.println("Netty 客户端连接成功!");
            } else {
                System.out.println("Netty 客户端连接失败: " + future.cause());
            }
            downLatch.countDown();
        };
    }

    @SneakyThrows
    public static void main(String[] args) {
        D d = new D();
        new Thread(()-> {
            try {
                new NettyClient().start(ctx->"执行了===", d);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        d.getDownLatch().await();
        System.out.println("isOpen: " + d.getChannel().isOpen());
        System.out.println("active: " + d.getChannel().isActive());
        d.getChannel().close();
        d.getChannel().close();
        Thread.sleep(10);
        System.out.println("active: " + d.getChannel().isActive());
        System.out.println("isOpen: " + d.getChannel().isOpen());
        Thread.sleep(5000);
    }

    @Data
    static class D{
        Channel channel;
        CountDownLatch downLatch = new CountDownLatch(1);
    }
}